/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: utility.h
 *
 * Purpose: helper type or function implementation
 *
 * Developer:
 *   wen.gu , 2020-04-14
 *
 * TODO:
 *
 ***************************************************************************/

#ifndef __ARA_CORE_UTILITY_H__
#define __ARA_CORE_UTILITY_H__
/******************************************************************************
 **    INCLUDES
 ******************************************************************************/

#include <cstddef>
#include <initializer_list>
#include <type_traits>
/******************************************************************************
 **    MACROS
 ******************************************************************************/


/******************************************************************************
 **    TYPE DEFINITIONS
 ******************************************************************************/
namespace ara
{
namespace core
{

/** todo, is this right? */
using Byte = unsigned char;
/******************************************************************************
 **    CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/

/** Denote an operation to be performed in-place */
struct in_place_t 
{
    explicit in_place_t() = default;
};

/** The singleton instance of in_place_t */
#if __cplusplus > 201402L
inline constexpr in_place_t in_place;
#else
constexpr in_place_t in_place;
#endif


/** Denote a type-distinguishing operation to be performed in-place */
template <typename T>
struct in_place_type_t
{
    explicit in_place_type_t ()=default;
};


/** Denote an index-distinguishing operation to be performed in-place */
template <size_t I>
struct in_place_index_t
{
    explicit in_place_index_t() = default;
};


/** template conjunction and disjunction only c++17 defined, so here as workaround */
#if __cplusplus < 201703L

/**for disjunction */
template <typename...>
struct Disjunction : std::false_type {};

template <typename B1>
struct Disjunction<B1> : B1 {};

template <typename B1, typename B2>
struct Disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};

template <typename B1, typename... Bs>
struct Disjunction<B1, Bs...> : std::conditional<B1::value, B1, Disjunction<Bs...>>::type {};

/**for conjunction */
// STRUCT TEMPLATE conjunction
template <bool _First_value, class _First, class... _Rest>
struct _Conjunction_l
{ // handle false trait or last trait
    using type = _First;
};

template <class _True, class _Next, class... _Rest>
struct _Conjunction_l<true, _True, _Next, _Rest...>
{ // the first trait is true, try the next one
    using type = typename _Conjunction_l<_Next::value, _Next, _Rest...>::type;
};

template <class... _Traits>
struct Conjunction : std::true_type {}; // If _Traits is empty, true_type

template <class _First, class... _Rest>
struct Conjunction<_First, _Rest...> : _Conjunction_l<_First::value, _First, _Rest...>::type
{
    // the first false trait in _Traits, or the last trait if none are false
};

#else
template <typename... Args>
using Disjunction = std::disjunction<Args...>;

template <class... _Traits>
using Conjunction = std::conjunction<_Traits...>;
#endif


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

/**These global functions allow uniform access to the data and size 
 * properties of contiguous containers. 
 */
template <typename Container>
constexpr auto data(Container& c) -> decltype(c.data())
{
    return c.data();
}

template <typename Container>
constexpr auto data(Container const& c) -> decltype(c.data())
{
    return c.data();
}

template <typename T, std::size_t N>
constexpr T* data(T(&array)[N]) noexcept
{
    // get pointer to data of array, todo, is this right??
    return (array);
}

template <typename E>
constexpr E const* data(std::initializer_list< E > il) noexcept
{
    // get pointer to data of initializer_list
    return (il.begin());
}

template <typename Container>
constexpr auto size(Container const& c) -> decltype(c.size())
{
    return c.size();
}

template <typename T, std::size_t N>
constexpr std::size_t size(T const (&array)[N]) noexcept
{
    return N;
}

template <typename Container>
constexpr auto empty(Container const& c) -> decltype(c.empty())
{
    return c.empty();
}

template <typename T, std::size_t N>
constexpr bool empty(T const (&array)[N]) noexcept
{
    return false;
}

template <typename E>
constexpr bool empty(std::initializer_list< E > il) noexcept
{
    // get dimension==0 for initializer_list
    return (il.size() == 0);
}

namespace internal_impl
{
    /** to check is a spec of a template */
    template<template<class...> class Target, class T>
    struct is_template_of
    {
        static const bool value = false;
    };

    template<template<class...> class Target, class...Args>
    struct is_template_of<Target, Target<Args...>>
    {
        static const bool value = true;
    };
} /** namespace internal_impl */


} /** namespace core */
} /** namespace ara */

#endif /** !__ARA_CORE_UTILITY_H__ */

